﻿using Microsoft.Extensions.DependencyInjection;
using Modules.Payroll.Comparers;
using Modules.System.User;
using PetaPoco;
using PmSoft;
using PmSoft.ApplicationContext;
using PmSoft.Caching;
using PmSoft.DBContext;
using PmSoft.Entity;
using PmSoft.Repositories;
using PmSoft.Utilities;
using System.Linq;

namespace Modules.Payroll.Repositories
{
    [UseDI(ServiceLifetime.Scoped)]
    public class WagePayrollDetailRepository : Repository<WagePayrollDetail, DefaultDbContext>
    {
        private readonly IApplicationContext applicationContext;
        private readonly static WagePayrollDetailComparer comparer = new();

        public WagePayrollDetailRepository(DefaultDbContext dbContext, IApplicationContext applicationContext) : base(dbContext, applicationContext)
        {
            this.applicationContext = applicationContext;
        }

        /// <summary>
        /// 批量创建或更新
        /// </summary>
        /// <param name="payrollId"></param>
        /// <param name="inWagePayrollDetails"></param>
        public void CreateOrUpdate(int payrollId, IEnumerable<WagePayrollDetail> inWagePayrollDetails)
        {
            var dbWagePayrollDetails = DbContext.Fetch<WagePayrollDetail>("WHERE payroll_id=@0", payrollId);
            var itemsToDelete = dbWagePayrollDetails.Except(inWagePayrollDetails, comparer).ToList();
            foreach (var item in itemsToDelete)
            {
                Delete(item);
            }
            var itemsToUpdate = dbWagePayrollDetails.Intersect(inWagePayrollDetails, comparer).ToList();
            foreach (var item in itemsToUpdate)
            {
                var detailInfo = inWagePayrollDetails.FirstOrDefault(m => comparer.Equals(m, item));
                if (detailInfo == null)
                    continue;
                detailInfo.Id = item.Id;
                Update(detailInfo);
            }
            var itemsToAdd = inWagePayrollDetails.Except(dbWagePayrollDetails, comparer).ToList();
            foreach (var item in itemsToAdd)
            {
                item.PayrollId = payrollId;
                Insert(item);
            }
        }

        public IEnumerable<WagePayrollDetail> GetPayrollDetailsByPayrollId(int payrollId)
        {
            int areaVersion = EntityCacheService.GetAreaVersion("PayrollId", payrollId);
            return GetTopEntities(1000, CachingExpirationType.ObjectCollection, () =>
            {
                return $"PayrollDetailsByPayrollId:{payrollId}:{areaVersion}";
            }, () =>
            {
                Sql sql = Sql.Builder
                .Select("id")
                .From("wage_payroll_detail")
                .Where("payroll_id=@0", payrollId);
                return sql;
            });
        }

        public IPagedList<WagePayrollDetail> GetPayrollDetails(WagePayrollQuery query, int pageIndex, int pageSize)
        {
            Sql sql = Sql.Builder.Select("wage_payroll_detail.id").From("wage_payroll_detail")
                    .InnerJoin("wage_payroll as b").On("wage_payroll_detail.payroll_id = b.id")
                    .InnerJoin("corp as c").On("b.corp_id = c.corp_id")
                    .InnerJoin("project_group as d").On("wage_payroll_detail.group_id = d.group_id")
                    .InnerJoin("person as e").On("wage_payroll_detail.person_id = e.person_id")
                    .InnerJoin("project as prj").On($"wage_payroll_detail.project_id=prj.project_id and prj.is_deleted=0");//项目关联
            #region 主管单位数据权限
            if (applicationContext.CurrentUser is IDeptUser deptUser && !deptUser.IsSuperAdministrator())
            {
                //sql.InnerJoin("project as prj").On($"wage_payroll_detail.project_id=prj.project_id and prj.is_deleted=0 and prj.industry_type=@0 ", deptUser.IndustryType);
                sql.Where("prj.industry_type=@0", deptUser.IndustryType);
                if (deptUser.Level == AdministrativeLevel.City)
                    sql.Append($" and prj.city_code={deptUser.CityCode}");
                if (deptUser.Level == AdministrativeLevel.Area)
                    sql.Append($" and prj.area_code={deptUser.AreaCode}");
            }
            #endregion
            if (!string.IsNullOrEmpty(query.Keywords))
            {
                sql.Where("(c.name Like @0 or d.name Like @0 or b.code Like @0 or e.name Like @0 or e.card_number Like @0 or prj.name Like @0)", "%" + StringUtility.StripSQLInjection(query.Keywords) + "%");
            }
            if (query.ProjectId.HasValue)
                sql.Where("wage_payroll_detail.project_id=@0", query.ProjectId);
            if (query.CorpId.HasValue)
                sql.Where("c.corp_id=@0", query.CorpId);
            if (query.Month.HasValue)
                sql.Where("wage_payroll_detail.month=@0", query.Month);
            if (query.CorpIds != null)
                sql.Where("c.corp_id in(@0)", query.CorpIds);
            if (query.StartDate.HasValue)
                sql.Where("wage_payroll_detail.month>=@0", query.StartDate);
            if (query.EndDate.HasValue)
                sql.Where("wage_payroll_detail.month<=@0", query.EndDate);
            sql.OrderBy("wage_payroll_detail.id DESC");
            return GetPagingEntities(pageSize, pageIndex, sql);
        }

        public IEnumerable<WagePayrollDetail> GetPayrollDetailsByPersonId(int personId)
        {
            int areaVersion = EntityCacheService.GetAreaVersion("PersonId", personId);
            return GetTopEntities(1000, CachingExpirationType.ObjectCollection, () =>
            {
                return $"PayrollDetailsByPersonId:{personId}:{areaVersion}";
            }, () =>
            {
                Sql sql = Sql.Builder
                .Select("id")
                .From("wage_payroll_detail")
                .Where("person_id=@0", personId);
                return sql;
            });
        }
    }
}